package com.dgut.lotterySystem.service.impl;

import com.dgut.lotterySystem.common.errorcode.ServiceErrorCodeConstants;
import com.dgut.lotterySystem.common.pojo.exception.ServiceException;
import com.dgut.lotterySystem.common.utils.JacksonUtil;
import com.dgut.lotterySystem.common.utils.RedisUtil;
import com.dgut.lotterySystem.common.utils.UUIDUtil;
import com.dgut.lotterySystem.controller.DrawPrizeController;
import com.dgut.lotterySystem.controller.param.DrawPrizeParam;
import com.dgut.lotterySystem.controller.param.ShowWinningRecordsParam;
import com.dgut.lotterySystem.dao.dataObject.*;
import com.dgut.lotterySystem.dao.mapper.*;
import com.dgut.lotterySystem.service.IDrawPrize;
import com.dgut.lotterySystem.service.dto.ShowWinningRecordsDTO;
import com.dgut.lotterySystem.service.enums.ActivityEnum;
import com.dgut.lotterySystem.service.enums.ActivityPrizeEnum;
import com.dgut.lotterySystem.service.enums.ActivityPrizeTierEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.dgut.lotterySystem.common.config.DirectRabbitConfig.EXCHANGE_NAME;
import static com.dgut.lotterySystem.common.config.DirectRabbitConfig.ROUTING;

@Service
public class DrawPrizeServiceImpl implements IDrawPrize {

    private static final Logger logger= LoggerFactory.getLogger(DrawPrizeServiceImpl.class);

    @Autowired
    private ActivityMapper activityMapper;
    @Autowired
    private ActivityPrizeMapper activityPrizeMapper;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private WinningRecordMapper winningRecordMapper;
    @Autowired
    private PrizeMapper prizeMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RedisUtil redisUtil;
    private final Long WINNING_TIME_OUT= Long.valueOf(2*24*60*60);
    private final String WINNING_RECORD_PREFIX="WINNING_RECORD_";
    @Override
    public void drawPrize(DrawPrizeParam param) {
        Map<String,String> map=new HashMap<>();
        map.put("messageId",String.valueOf(UUIDUtil.UUID_32()));
        map.put("messageData", JacksonUtil.writeValueAsString(param));
        rabbitTemplate.convertAndSend(EXCHANGE_NAME,ROUTING,map);
        logger.info("mq消息发送成功，map="+JacksonUtil.writeValueAsString(map));
    }

    @Override
    public Boolean checkDrawPrizeParam(DrawPrizeParam param) {
        if(param==null){
            logger.info("校验抽奖请求失败！失败原因：{}",ServiceErrorCodeConstants.ACTIVITY_PRIZE_PARAM_NULL.getMsg());
            return false;
            //throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_PRIZE_PARAM_NULL);
        }
        //校验活动和活动奖品是否存在
        ActivityDO activityDO=activityMapper.findActivityInfoById(param.getActivityId());
        ActivityPrizeDO activityPrizeDO=activityPrizeMapper.selectByActivityPrizeId(param.getActivityId(),param.getPrizeId());
        if(activityDO==null||activityPrizeDO==null){
            logger.info("校验抽奖请求失败！失败原因：{}",ServiceErrorCodeConstants.ACTIVITY_OR_PRIZE_NULL.getMsg());
            return false;
            //throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_OR_PRIZE_NULL);
        }
        //校验活动和活动奖品是否有效
        if(activityDO.getStatus().equalsIgnoreCase(ActivityEnum.COMPLETED.name())){
            logger.info("校验抽奖请求失败！失败原因：{}",ServiceErrorCodeConstants.ACTIVITY_COMPLETED.getMsg());
            return false;
            //throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_COMPLETED);
        }
        if(activityPrizeDO.getStatus().equalsIgnoreCase(ActivityPrizeEnum.COMPLETED.name())){
            logger.info("校验抽奖请求失败！失败原因：{}",ServiceErrorCodeConstants.ACTIVITY_PRIZE_COMPLETED.getMsg());
            return false;
            //throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_PRIZE_COMPLETED);
        }
        //校验数量时候有效
        if(param.getWinnerList().size()!=activityPrizeDO.getPrizeAmount()){
            logger.info("校验抽奖请求失败！失败原因：{}",ServiceErrorCodeConstants.ACTIVITY_PRIZE_USER_AMOUNT_UNEQUAL.getMsg());
            return false;
            //throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_PRIZE_USER_AMOUNT_UNEQUAL);
        }
        return true;
    }

    @Override
    public List<WinningRecordDO> saveWinningRecord(DrawPrizeParam param) {
        //查到活动，奖品，用户，活动奖品信息
        ActivityDO activityDO=activityMapper.findActivityInfoById(param.getActivityId());

        ActivityPrizeDO activityPrizeDO=activityPrizeMapper.SelectByActivityPrizeId(param.getActivityId(),param.getPrizeId());
        PrizeDO prizeDO=prizeMapper.selectById(param.getPrizeId());

        List<Long> userIds=param.getWinnerList().stream()
                .map(DrawPrizeParam.Winner::getUserId)
                .collect(Collectors.toList());
        List<UserDO> userDOList= userMapper.batchSelectByIds(userIds);
        if(activityDO==null
                ||activityPrizeDO==null
                ||prizeDO==null
                || CollectionUtils.isEmpty(userDOList)){
            throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_DETAIL_UPDATE_ERROR);
        }

        List<WinningRecordDO> winningRecordDOList=userDOList.stream().map(userDO -> {
            WinningRecordDO winningRecordDO=new WinningRecordDO();
            winningRecordDO.setActivityId(activityDO.getId());
            winningRecordDO.setActivityName(activityDO.getActivityName());
            winningRecordDO.setPrizeId(prizeDO.getId());
            winningRecordDO.setPrizeName(prizeDO.getName());
            winningRecordDO.setPrizeTier(activityPrizeDO.getPrizeTiers());
            winningRecordDO.setWinnerId(userDO.getId());
            winningRecordDO.setWinnerEmail(userDO.getEmail());
            winningRecordDO.setWinnerName(userDO.getUserName());
            winningRecordDO.setWinnerPhoneNumber(userDO.getPhoneNumber());
            winningRecordDO.setWinningTime(param.getWinningTime());
            return winningRecordDO;
        }).collect(Collectors.toList());
        winningRecordMapper.batchInsert(winningRecordDOList);

        //缓存中奖者记录
        //缓存奖品维度的中奖记录
        //key:activityId+prizeId
        cacheWinningRecords(param.getActivityId()+"_"+param.getPrizeId(),winningRecordDOList,WINNING_TIME_OUT);
        //缓存活动维度的中奖记录
        if(activityDO.getStatus()
                .equalsIgnoreCase(ActivityEnum.COMPLETED.name())){
            List<WinningRecordDO> allList=winningRecordMapper.batchSelectByActivityId(param.getActivityId());
            cacheWinningRecords(String.valueOf(param.getActivityId()),allList,WINNING_TIME_OUT);
        }
        return winningRecordDOList;
    }

    @Override
    public void deleteRecords(Long activityId, Long prizeId) {
        if(activityId==null){
            logger.warn("删除中奖记录，参数，活动id为空");
            return;
        }
        //删除表中的数据
        winningRecordMapper.deleteRecordByAPId(activityId,prizeId);
        //删除缓存数据
        //有奖品id，就一定要删除奖品缓存信息
        //即使没有奖品id信息，也要删除活动缓存，因为活动缓存要在奖品全被抽完的情况下才会存在
        if(prizeId!=null){
            deleteRedisWinningRecord(activityId+"_"+prizeId);
        }
        deleteRedisWinningRecord(String.valueOf(activityId));
    }

    @Override
    public List<ShowWinningRecordsDTO> ShowWinningRecords(ShowWinningRecordsParam param) {
        String key=param.getPrizeId()==null?
                String.valueOf(param.getActivityId())
                :param.getActivityId()+"_"+param.getPrizeId();
        List<WinningRecordDO> winningRecordDOList=getWinningRecords(key);
        if(!CollectionUtils.isEmpty(winningRecordDOList)){
            return convertShowWinningRecordsDTO(winningRecordDOList);
        }

        //redis 为空，查库
        winningRecordDOList=winningRecordMapper.batchSelectByAPId(param.getActivityId(),param.getPrizeId());
        List<ShowWinningRecordsDTO> result=convertShowWinningRecordsDTO(winningRecordDOList);
        //存redis
        if(CollectionUtils.isEmpty(winningRecordDOList)){
            logger.info("查询的库中中奖记录为空，{}",JacksonUtil.writeValueAsString(param));
            return Arrays.asList();
        }

        cacheWinningRecords(key,winningRecordDOList,WINNING_TIME_OUT);
        return result;
    }

    private List<ShowWinningRecordsDTO> convertShowWinningRecordsDTO(List<WinningRecordDO> winningRecordDOList) {
        if(CollectionUtils.isEmpty(winningRecordDOList)){
            logger.info("convertShowWinningRecordsDTO winningRecordDOList列表为空");
            return Arrays.asList();
        }
        return winningRecordDOList.stream().map(winningRecordDO->{
            ShowWinningRecordsDTO winningRecordsDTO=new ShowWinningRecordsDTO();
            winningRecordsDTO.setWinningId(winningRecordDO.getId());
            winningRecordsDTO.setWinnerName(winningRecordDO.getWinnerName());
            winningRecordsDTO.setPrizeName(winningRecordDO.getPrizeName());
            winningRecordsDTO.setPrizeTier(ActivityPrizeTierEnum.forName(winningRecordDO.getPrizeTier()));
            winningRecordsDTO.setWinningTime(winningRecordDO.getWinningTime());
            return winningRecordsDTO;
        }).collect(Collectors.toList());
    }

    private void deleteRedisWinningRecord(String key) {
    }

    private void cacheWinningRecords(String key, List<WinningRecordDO> winningRecordDOList, Long winning_time_out) {
        String str="";
        try{
            if(!StringUtils.hasText(key)
                    ||CollectionUtils.isEmpty(winningRecordDOList)){
                logger.warn("要缓存的内容为空，key:{},value:{}",WINNING_RECORD_PREFIX+key,JacksonUtil.writeValueAsString(winningRecordDOList));
                return;
            }
            str=JacksonUtil.writeValueAsString(winningRecordDOList);
            System.out.println("===============================================================");
            System.out.println(str);
            System.out.println("===============================================================");
            redisUtil.set(WINNING_RECORD_PREFIX+key,str,winning_time_out);
        }catch (Exception e){
            logger.warn("缓存活动信息异常，key:{},value:{}",WINNING_RECORD_PREFIX+key,str);
        }
    }

    private List<WinningRecordDO> getWinningRecords(String key){
        try{
            if(!StringUtils.hasText(key)){
                logger.warn("要获取的活动缓存数据key={}异常",key);
                return Arrays.asList();
            }
            String str=redisUtil.get(WINNING_RECORD_PREFIX+key);
            if(StringUtils.hasText(str)){
                List<WinningRecordDO> winningRecordDOList=JacksonUtil.readListValue(str,WinningRecordDO.class);
                return winningRecordDOList;
            }
        }catch (Exception e){
            logger.warn("获取到的活动缓存数据为空，key={}",WINNING_RECORD_PREFIX+key);

        }
        return Arrays.asList();
    }
}
